package xyz.cerberu.cet.spider.service;

import com.spider.core.SpiderClient;
import com.spider.core.SpiderConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import xyz.cerberu.cet.anime.dao.AnimeDao;
import xyz.cerberu.cet.anime.domain.Anime;
import xyz.cerberu.cet.global.domain.Global;
import xyz.cerberu.cet.spider.anime.spider.AnimeSpider;
import xyz.cerberu.cet.spider.exception.ResourceTypeException;
import xyz.cerberu.cet.spider.resource.spider.Logic.ResourceLogic;
import xyz.cerberu.cet.spider.resource.spider.ResourceSpider;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.util.List;

/**
 * @author β世界
 * Created on 22:27
 * @Description 爬虫管理服务
 */
@Service
public class SpiderManagerService {
    private static final Logger logger = LoggerFactory.getLogger(SpiderManagerService.class);
    /** 爬虫设置内容 **/
    private final SpiderConfig resourceSpiderConfig;
    private static final String NAME = "NAME";
    private static final String ID = "ID";
    private static final String PREFIX_URL = "https://www.dmhy.org/topics/list?keyword=";
    /** 资源的爬虫逻辑 **/
    private final ResourceLogic resourceLogic;
    private final AnimeDao animeDao;
    private final AnimeSpider animeSpider;
    private final ResourceSpider resourceSpider;

    @Autowired
    public SpiderManagerService(SpiderConfig resourceSpiderConfig, ResourceLogic resourceLogic, AnimeDao animeDao, Global global, AnimeSpider animeSpider, ResourceSpider resourceSpider) {
        this.resourceSpiderConfig = resourceSpiderConfig;
        this.resourceLogic = resourceLogic;
        this.animeDao = animeDao;
        this.animeSpider = animeSpider;
        this.resourceSpider = resourceSpider;
    }

    /**
     * 指定时间更新动漫
     * @author β世界 on 13:59 2021/5/31
     * @param year: 年份
     * @param month: 月份
     * @return void
     **/
    @Async(value = "taskExecutor")
    public void appointTimeUpdateAnime(Integer year, Integer month){
        animeSpider.assignTimeUpdateAnime(year,month);
    }

    @Async(value = "taskExecutor")
    public void appointTimeUpdateResource(Integer year, Integer month){
        java.sql.Date startDate;
        java.sql.Date endDate;
        // 如果时间是0那就是全月份
        if(month.equals(0)){
            startDate = java.sql.Date.valueOf(LocalDate.of(year,1,1));
            endDate = java.sql.Date.valueOf(LocalDate.of(year,12,31));
        }else{
            startDate = java.sql.Date.valueOf(LocalDate.of(year,month,1));
            endDate = java.sql.Date.valueOf(LocalDate.of(year,month,31));
        }
        // 根据这个时间的动漫，去爬取
        List<Anime> animeList = animeDao.selectRangeAnimeByWeek(startDate,endDate,0);
        resourceSpider.updateResourceByAnime(animeList);
    }

    /**
     * @author β世界 on 13:12 2021/1/17
     * 用于区分获取单个动漫的方式
     * @param animeInfo: 动漫信息
     * @param type: 获取的类型
     **/
    public void captureResource(String animeInfo,String type) throws UnsupportedEncodingException {
        Anime anime;
        switch (type){
            case NAME:
                // 通过name的方式来获取动漫信息
                anime = new Anime();
                anime.setAnime_name(animeInfo);
                captureResourceByName(anime);
                break;
            case ID:
                // 通过id的方式来获取动漫的信息
                anime = animeDao.selectAnimeByID(animeInfo);
                captureResourceByName(anime);
                break;
            default:
                // 如果处理类型不是上面所列出来的，那么就抛出异常
                throw new ResourceTypeException("处理类型错误");
        }
    }

    /**
     * @author β世界 on 19:42 2020/8/10
     * 爬取一个动漫的资源，根据动漫名来爬取资源
     * 需要进行异步的任务调度
     * @param anime: 动漫名
     **/
    @Async(value = "taskExecutor")
    protected void captureResourceByName(Anime anime) throws UnsupportedEncodingException {
        SpiderClient client = resourceSpiderConfig.create();
        // 设置爬虫逻辑
        client.addProcessLogic(resourceLogic);
        String urlName = PREFIX_URL + URLEncoder.encode(anime.getAnime_name(),"UTF-8") + "&sort_id=2&team_id=0&order=date-desc";
        // 检查是否添加别名来处理
        if(anime.getAlias() != null && !"".equals(anime.getAlias())){
            String urlAlias = PREFIX_URL + URLEncoder.encode(anime.getAlias(),"UTF-8") + "&sort_id=2&team_id=0&order=date-desc";
            client.addSeedUrl(urlAlias);
        }
        // 添加根种子链接
        client.addSeedUrl(urlName);
        // 爬取开始
        client.start();
        int count = 0;

    }

    /**
     * @author β世界 on 13:14 2021/1/17
     * 执行爬虫固定的爬取任务
     * @param task: 任务名
     **/
    public void spiderTask(String task) throws InvocationTargetException, IllegalAccessException {
        // 通过反射的方式来调用这个任务
        Method method;
        // 判断这个任务存在于那个爬虫
        if((method = contain(AnimeSpider.class.getMethods(),task)) != null){
            executeTask(method,animeSpider);
        }else if((method = contain(ResourceSpider.class.getMethods(),task)) != null){
            executeTask(method,resourceSpider);
        }
    }

    /**
     * @author β世界 on 20:26 2021/1/17
     * 执行任务
     * @param method: 方法
     * @param spider: 爬虫的具体实现类
     **/
    @Async
    public void executeTask(Method method,Object spider) throws InvocationTargetException, IllegalAccessException {
        method.invoke(spider);
    }

    /**
     * @author β世界 on 18:59 2021/1/17
     * 检查一个类中是否存在方法
     * @param methods: 方法组
     * @param function: 方法名
     * @return java.lang.reflect.Method
     **/
    private Method contain(Method[] methods,String function){
        for(Method method : methods){
            if(method.getName().equals(function)){
                return method;
            }
        }
        return null;
    }

}
